﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;

using Buddy.Common;
using Buddy.Common.Plugins;
using Buddy.Common.Xml;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Enums;
using Buddy.Swtor.Objects;
using Buddy.XmlEngine;

namespace Equipper
{
    public class Equipper : IPlugin
    {
        #region Implementation of IEquatable<IPlugin>

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <returns>
        /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
        /// </returns>
        /// <param name="other">An object to compare with this object.</param>
        public bool Equals(IPlugin other)
        {
            return other.Name == Name;
        }

        #endregion

        #region Implementation of IPlugin

        public string Author { get { return "BobDole"; } }

        public Version Version { get { return new Version(0, 1); } }

        public string Name { get { return "Equipper"; } }

        public string Description { get { return "Automatically equip items based on their stat weights"; } }

        public Window DisplayWindow { get { return null; } }
        private static TorPlayer Me { get { return BuddyTor.Me; } }
        private static TorCharacter TorMe { get { return BuddyTor.Me; } }
        public bool isNew;

        /// <summary> Executes the pulse action. This is called every "tick" of the bot. </summary>
        public void OnPulse()
        {

        }

        /// <summary> Executes the initialize action. This is called at initial bot startup. (When the bot itself is started, not when Start() is called) </summary>
        public void OnInitialize()
        {
            //Set up currentEquipment list
            currentEquip = new CharEquip(BuddyTor.Me.InventoryEquipped);

            foreach (TorItem item in BuddyTor.Me.InventoryEquipped)
            {
                Log("Currently wearing: " + item.Name);
            }
        }

        /// <summary> Executes the shutdown action. This is called when the bot is shutting down. (Not when Stop() is called) </summary>
        public void OnShutdown()
        {
            
        }

        /// <summary> Executes the enabled action. This is called when the user has enabled this specific plugin via the GUI. </summary>
        public void OnEnabled()
        {
            GameEvents.InventorySlotsChanged += invChange;
        }

        /// <summary> Executes the disabled action. This is called whent he user has disabled this specific plugin via the GUI. </summary>
        public void OnDisabled()
        {
            GameEvents.InventorySlotsChanged -= invChange;
        }

        public static void Log(string message)
        {
            Logging.Write("[Equipper] " + message);
        }

        #endregion

        private CharEquip currentEquip;

        public void invChange()
        {
            if (BuddyTor.Me.InCombat)
            {
                return;
            }
            using (BuddyTor.Memory.AcquireFrame())
            {
                foreach (TorItem item in BuddyTor.Me.InventoryEquipment)
                {
                    if (!item.IsEquipable || item.IsEnhancement)
                        continue;
                    //If class can wear item
                    if (BuddyTor.Me.CanEquipItem(item) == ContainerResult.Ok)
                    {
                        checkItem(item);
                    }
                }
            }
        }

        public bool checkItem(TorItem item)
        {
            bool better = false;
            List<EquipmentSlot> matchingSlots = new List<EquipmentSlot>();

            foreach (SlotId s in item.SlotTypes)
            {
                matchingSlots = currentEquip.EquipSlot.Where(f => f.Slot == s).ToList();
                if (matchingSlots.Any())
                {
                    break;
                }
            }
            if (matchingSlots.Count < 1)
            {
                return false;
            }
            else
            {
                better = compareWeights(item, matchingSlots);
            }

            return better;
        }

        private bool compareWeights(TorItem item, List<EquipmentSlot> matchingSlots)
        {
            float newItemWeight = calculateWeight(item.GetItemStats(true));
            EquipmentSlot itemToReplace = null;

            foreach (EquipmentSlot currItem in matchingSlots)
            {
                if (currItem.Item != null)
                {
                    currItem.Weight = calculateWeight(currItem.Item.GetItemStats(true));
                }
                else
                {
                    currItem.Weight = 0;
                }
            }
            //Compare new item weight to existing items to see if it's higher to at least one
            foreach (EquipmentSlot currItem in matchingSlots)
            {
                if (newItemWeight > currItem.Weight)
                {
                    //Equipper.Log("Comparing: " + item.Name + " - Weight: " + newItemWeight + " vs " 
                    //    + ((itemToReplace.Item != null) ? itemToReplace.Item.Name : "[Blank Slot]") + " - Weight: " + itemToReplace.Weight);
                    //If we have 2 items to replace (eg. relics) we want to replace the lower weighted one.
                    itemToReplace = matchingSlots.OrderBy(f => f.Weight).FirstOrDefault();
                    break;
                }
            }
            if (itemToReplace != null)
            {
                //Equip item
                Equipper.Log("Equipping: " + item.Name + " - Weight: " + newItemWeight + " vs " + itemToReplace.Weight 
                    + " of " + ((itemToReplace.Item != null) ? itemToReplace.Item.Name : "[Blank Slot]"));
                BuddyTor.Me.EquipItem(item);
                //item.EquipNoConfirm();
                return true;
            }
            else
            {
                return false;
            }

        }

        private float calculateWeight(Dictionary<ModStat, float> statList)
        {
            float total = 0;
            float weight;
            //Loop through each stat in the item
            foreach (KeyValuePair<ModStat, float> stat in statList)
            {
                //If we have that stat weighted, calculate its subtotal and add to total. Otherwise, skip it.
                if (currentEquip.StatWeights.TryGetValue(stat.Key, out weight))
                {
                    //Multiply item's stat value by the weight
                    total += stat.Value * weight;
                }
            }

            return total;
        }
    }
}
